home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MySIVC.p < prev    next >
Encoding:
Text File  |  1997-01-30  |  12.0 KB  |  442 lines  |  [TEXT/CWIE]

  1. unit MySIVC;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types;
  7.  
  8.     const
  9.         PC_UseSIVC = 'SIVC';
  10.         PC_FirstCheckSIVC = 'SIVd';
  11.         PC_LastCheckSIVCQuantum = 'SICl';
  12.         PC_CheckSIVCPeriod = 'SIVc';
  13.         PC_LastSIVC = 'SIVL';
  14.         PC_SIVCUsers = 'SIVU';
  15.         
  16.     type
  17.         SIVCNewVersionCallBack = procedure(data:Handle; latest_version:Str31);
  18.         SIVCGetSOCKSServerCallBack = procedure(var server:Str255);
  19.         SIVCManualQueryCallBack = procedure(err:OSErr; newversion:Boolean; data:Handle; latest_version:Str31);
  20.     
  21.     var
  22.         first_ever_sivc: Boolean; { if this is the first time - warn the user! }
  23.         
  24.     procedure StartupSIVC;
  25.     procedure ConfigureSIVC(newversion : SIVCNewVersionCallBack; getsocks:SIVCGetSOCKSServerCallBack);
  26.         
  27.     procedure ManualQuery(mcresult: SIVCManualQueryCallBack);
  28.     function CanManualQuery:Boolean;
  29.     
  30. implementation
  31.  
  32.     uses
  33.         Errors, Resources, MyNewPreferences, MyTransport, DNR, MyMathUtils, MyTranslateISO,
  34.         MyTypes, MyHandleFile, MySocks, MyStrings, MyVersionResource, MyUtils, MyStartup, MySystemGlobals;
  35.         
  36.     const
  37.         sivc_id = 932;
  38.         sivc_default_port = 7124;
  39.         idle_til_period = 10 * 60 *60; { only even consider checking every 10 minutes }
  40.         timeout_period = 120 * 60;
  41.  
  42.     type
  43.         SIVCStrings = (SS_None, SS_Server, SS_SOCKSServer);
  44.         SIVCState = (ST_None, ST_SOCKS_DNR, ST_Connecting, ST_SendSOCKS, ST_SendQuery, ST_WaitClose, ST_Finished);
  45.         SIVCMaunalState = (MS_None, MS_Want, MS_Doing);
  46.     
  47.     var
  48.         newversion_callback : SIVCNewVersionCallBack;
  49.         getsocks_callback : SIVCGetSOCKSServerCallBack;
  50.         mcresult_callback : SIVCManualQueryCallBack;
  51.         state : SIVCState;
  52.         tref: TransportRef;
  53.         idle_til:longint;
  54.         use_socks:boolean;
  55.         sivc_dnr:Ptr;
  56.         sivc_port:integer;
  57.         sivc_addr: ipAddr;
  58.         socks_port: integer;
  59.         vers:versionRecord;
  60.         app_creator: string[4];
  61.         query_result:Handle;
  62.         manual_state:SIVCMaunalState;
  63.         timeout:longint;
  64.         last_char_was_cr: boolean;
  65.     
  66.     procedure ServerToHostPort(s:Str255; defport:integer; var host:Str255; var port:integer);
  67.         var
  68.             portstr:Str255;
  69.             n:longint;
  70.     begin
  71.         if SplitAt(s, ':', host, portstr) | SplitAt(s, ' ', host, portstr) then begin
  72.             StringToNum(portstr,n);
  73.             port := n;
  74.         end else begin
  75.             host := s;
  76.             port := defport;
  77.         end;
  78.     end;
  79.     
  80.     procedure GetSOCKSServer(var server:Str255);
  81.     begin
  82.         server := '';
  83.         if getsocks_callback <> nil then begin
  84.             getsocks_callback(server);
  85.         end;
  86.         if server = '' then begin
  87.             GetIndString(server,sivc_id,ord(SS_SOCKSServer));
  88.         end;
  89.     end;
  90.     
  91.     procedure ReleaseConnection;
  92.     begin
  93.         TransportAbortDNR(sivc_dnr);
  94.         TransportDestroy(tref);
  95.     end;
  96.  
  97.     function SendQuery:OSErr;
  98.         var
  99.             query:Str255;
  100.             count:integer;
  101.             err: OSErr;
  102.     begin
  103.         if (manual_state = MS_Doing) then begin
  104.             query := 'Query: ProductInfoManual';
  105.         end else begin
  106.             query := 'Query: ProductInfoAuto';
  107.         end;
  108.         query := concat(query, cr,
  109.                                 'Product: ', vers.name, cr,
  110.                                 'ProductID: macos:APPL/',app_creator,cr,
  111.                                 'Version: ',HexNN(longint(vers.numericVersion),8),cr,
  112.                                 cr);
  113.         count := MacToNet(@query[1],length(query));
  114.         
  115.         err := TransportSend(tref, @query[1], count);
  116.         SendQuery := err;
  117.     end;
  118.     
  119.     function SendSocks:OSErr;
  120.         var
  121.             query:SocksRecordSmall;
  122.     begin
  123.         query.version := socks_version;
  124.         query.cmd := socks_connect;
  125.         query.port := sivc_port;
  126.         query.ip := sivc_addr;
  127.         SendSocks := TransportSend(tref, @query, SizeOf(query));
  128.     end;
  129.     
  130.     function IsField(field:Str255; var line:Str255):Boolean;
  131.         var
  132.             s:Str255;
  133.     begin
  134.         IsField := false;
  135.         if IsPrefix(line, field) then begin
  136.             s := Trim(TPcopy(line, length(field)+1, 255));
  137.             if (s<>'') & (s[1] = ':') then begin
  138.                 line := Trim(TPcopy(s, 2, 255));
  139.                 IsField := true;
  140.             end;
  141.         end;
  142.     end;
  143.     
  144.     procedure ProcessResult;
  145.         var
  146.             hf:HandleFile;
  147.             line:Str255;
  148.             latest_version:longint;
  149.             query_interval, users:longint;
  150.             ver:NumVersion;
  151.             new:boolean;
  152.     begin
  153.         hf.data := query_result;
  154.         hf.pos := 0;
  155.         hf.crlf := CL_CR;
  156.         hf.error := noErr;
  157.         latest_version := -1;
  158.         while ReadFromHandleFile(hf, line) do begin
  159.             if IsField('ReleaseVersion', line) then begin
  160.                 latest_version := HexToNum(line);
  161.             end else if IsField('AutoQueryIntervalM', line) then begin
  162.                 StringToNum(line, query_interval);
  163.                 if (query_interval >= 1440) & (query_interval < 136800) then begin { 1 to 95 days }
  164.                     prefs.SetTagLong(PC_CheckSIVCPeriod, query_interval);
  165.                 end;
  166.             end else if IsField('UserCount',line) then begin
  167.                 StringToNum(line, users);
  168.                 prefs.SetTagLong(PC_SIVCUsers, users);
  169.             end;
  170.         end;
  171.         new := (latest_version > longint(vers.numericVersion));
  172.         line := '';
  173.         if (latest_version <> -1) then begin
  174.             ver := NumVersion(latest_version);
  175.             line:=concat(NumToStr(ver.majorRev),'.',
  176.                                 NumToStr(BAND(ver.minorAndBugRev div 16,$0F)),'.',
  177.                                 NumToStr(BAND(ver.minorAndBugRev,$0F))
  178.                                 );
  179.             if (ver.stage<>$80) or (ver.nonRelRev<>0) then begin
  180.                 case ver.stage of 
  181.                     $20:begin
  182.                         line:=concat(line,'d');
  183.                     end;
  184.                     $40:begin
  185.                         line:=concat(line,'a');
  186.                     end;
  187.                     $60:begin
  188.                         line:=concat(line,'b');
  189.                     end;
  190.                     $80:begin
  191.                         line:=concat(line,'f');
  192.                     end;
  193.                     otherwise begin
  194.                         line:=concat(line,'<',NumToStr(ver.stage),'>');
  195.                     end;
  196.                 end;
  197.                 if ver.nonRelRev <> 0 then begin
  198.                     line:=concat(line,NumToStr(ver.nonRelRev));
  199.                 end;
  200.             end;
  201.         end;
  202.         if (manual_state = MS_Doing) then begin
  203.             if mcresult_callback <> nil then begin
  204.                 mcresult_callback(noErr, new, query_result, line);
  205.                 mcresult_callback := nil;
  206.             end;
  207.         end else begin
  208.             if new & (newversion_callback <> nil) then begin
  209.                 newversion_callback(query_result, line);
  210.             end;
  211.         end;
  212.     end;
  213.     
  214.     function GetThisQuantum:longint;
  215.         var
  216.             date,first_checked_date: UInt32;
  217.             check_period: longint;
  218.     begin
  219.         GetDateTime(date);
  220.         prefs.GetTagLong(PC_FirstCheckSIVC,first_checked_date);
  221.         prefs.GetTagLong(PC_CheckSIVCPeriod,check_period);
  222.         GetThisQuantum := (date - first_checked_date) div 60 div check_period;
  223.     end;
  224.     
  225.     procedure IdleSIVC;
  226.         var
  227.             last_quantum:longint;
  228.             s:Str255;
  229.             err:OSErr;
  230.             socksresult:SocksRecordSmall;
  231.             space: packed array[1..256] of Byte;
  232.             count: integer;
  233.             tstate :TCPStateType;
  234.             date:UInt32;
  235.             received:longint;
  236.             result: OSStatus;
  237.             junk: OSErr;
  238.     begin
  239.         if (state <> ST_Finished) & ((manual_state <> MS_None) | (TickCount > idle_til)) then begin
  240.             err := noErr;
  241.             if (manual_state = MS_Want) & (state = ST_None) then begin
  242.                 manual_state := MS_Doing;
  243.             end;
  244.             if (state <> ST_None) & (state <> ST_SOCKS_DNR) & (TickCount > timeout) then begin
  245.                 err := -8;
  246.             end else if not prefs.GetTagBoolean(PC_UseSIVC) & (manual_state <> MS_Doing) then begin
  247.                 err := -4;
  248.             end else begin
  249.                 case state of
  250.                     ST_None: begin
  251.                         last_char_was_cr := false;
  252.                         prefs.GetTagLong(PC_LastCheckSIVCQuantum,last_quantum);
  253.                         if (GetThisQuantum <> last_quantum) or (manual_state = MS_Doing) then begin
  254.                             SetHandleSize(query_result,0);
  255.                             GetSOCKSServer(s);
  256.                             use_socks := s<>'';
  257.                             GetIndString(s,sivc_id,ord(SS_Server));
  258.                             ServerToHostPort(s,sivc_default_port,s,sivc_port);
  259.                             if use_socks then begin
  260.                                 err := TransportNameToAddr(s, sivc_dnr);
  261.                                 state := ST_SOCKS_DNR;
  262.                             end else begin
  263.                                 timeout := TickCount + timeout_period;
  264.                                 err := TransportOpenActiveConnection(tref, concat(s, ':', NumToStr(sivc_port)), 0, 0);
  265.                                 if err = noErr then begin
  266.                                     err := TransportHandleTransfers(tref);
  267.                                 end;
  268.                                 state := ST_Connecting;
  269.                             end;
  270.                         end else begin
  271.                             err := -1;
  272.                         end;
  273.                     end;
  274.                     ST_SOCKS_DNR:begin
  275.                         TransportGetNameToAddrResult(sivc_dnr, result, nil, @sivc_addr, 1);
  276.                         case result of
  277.                             inProgress: begin
  278.                                 err := noErr;
  279.                             end;
  280.                             noErr: begin
  281.                                 timeout := TickCount + timeout_period;
  282.                                 GetSOCKSServer(s);
  283.                                 ServerToHostPort(s, socks_default_port, s, socks_port);
  284.                                 err := TransportOpenActiveConnection(tref, concat(s, ':', NumToStr(socks_port)), 0, 0);
  285.                                 if err = noErr then begin
  286.                                     err := TransportHandleTransfers(tref);
  287.                                 end;
  288.                                 state := ST_Connecting;
  289.                             end;
  290.                             otherwise begin
  291.                                 err := result;
  292.                             end;
  293.                         end;
  294.                     end;
  295.                     ST_Connecting:begin
  296.                         if not (TransportGetConnectionState(tref) in [T_WaitingForOpen, T_Bored, T_Opening]) then begin
  297.                             if TransportGetConnectionState(tref) = T_Established then begin
  298.                                 if use_socks then begin
  299.                                     err := SendSocks;
  300.                                     state := ST_SendSOCKS;
  301.                                 end else begin
  302.                                     err := SendQuery;
  303.                                     state := ST_SendQuery;
  304.                                 end;
  305.                             end else begin
  306.                                 err := -6;
  307.                             end;
  308.                         end;
  309.                     end;
  310.                     ST_SendSOCKS:begin
  311.                         if TransportGetConnectionState(tref) = T_Established then begin
  312.                             if TransportCharsAvailable(tref) >= SizeOf(socksresult) then begin
  313.                                 err := TransportReceive(tref, @socksresult, SizeOf(socksresult), received);
  314.                                 if (err = noErr) & (received <> SizeOf(socksresult)) &  (socksresult.cmd <> socks_result) then begin
  315.                                     err := -2;
  316.                                 end;
  317.                                 if err = noErr then begin
  318.                                     err := SendQuery;
  319.                                     state := ST_SendQuery;
  320.                                 end;
  321.                             end;
  322.                         end else begin
  323.                             err := -72;
  324.                         end;
  325.                     end;
  326.                     ST_SendQuery:begin
  327.                         tstate := TransportGetConnectionState(tref);
  328.                         count := Min(TransportCharsAvailable(tref),SizeOf(space));
  329.                         if (tstate <> T_Dead) & (tstate <> T_Bored) & ((tstate <> T_PleaseClose) | (count > 0))then begin
  330.                             if count>0 then begin
  331.                                 err := TransportReceive(tref, @space, count, received);
  332.                                 if err = noErr then begin
  333.                                     count := NetToMac( @space, received, last_char_was_cr );
  334.                                     err:=PtrAndHand(@space,query_result,count);
  335.                                 end;
  336.                             end;
  337.                         end else begin
  338.                             if tstate = T_PleaseClose then begin
  339.                                 TransportSendClose(tref);
  340.                             end;
  341.                             GetDateTime(date);
  342.                             prefs.SetTagLong(PC_LastSIVC,date);
  343.                             ProcessResult;
  344.                             if (manual_state <> MS_Doing) then begin
  345.                                 prefs.SetTagLong(PC_LastCheckSIVCQuantum, GetThisQuantum);
  346.                             end;
  347.                             state := ST_WaitClose;
  348.                             junk := WritePrefsData;
  349.                         end;
  350.                     end;
  351.                     ST_WaitClose:begin
  352.                         tstate := TransportGetConnectionState(tref);
  353.                         if (tstate = T_Dead) or (tstate = T_Bored) then begin
  354.                             err := -3;
  355.                         end;
  356.                     end;
  357.                 end;
  358.             end;
  359.             if err <> noErr then begin
  360.                 ReleaseConnection;
  361.                 idle_til := TickCount + idle_til_period;
  362.                 state := ST_None;
  363.                 if (manual_state = MS_Doing) then begin
  364.                     manual_state := MS_None;
  365.                     if mcresult_callback <> nil then begin
  366.                         mcresult_callback(err, false, nil, '');
  367.                         mcresult_callback := nil;
  368.                     end;
  369.                 end;
  370.             end;
  371.         end;
  372.     end;
  373.     
  374.     function CanManualQuery:Boolean;
  375.     begin
  376.         CanManualQuery := (manual_state = MS_None) & (state <> ST_Finished);
  377.     end;
  378.     
  379.     procedure ManualQuery(mcresult: SIVCManualQueryCallBack);
  380.     begin
  381.         if CanManualQuery then begin
  382.             mcresult_callback := mcresult;
  383.             manual_state := MS_Want;
  384.         end else begin
  385.             if mcresult <> nil then begin
  386.                 mcresult(aspServerBusy,false,nil,'');
  387.             end;
  388.         end;
  389.     end;
  390.  
  391.     function InitSIVC(var msg: integer): OSStatus;
  392.         var
  393.             bndl:Handle;
  394.             date:UInt32;
  395.             junk: OSErr;
  396.     begin
  397. {$unused(msg)}
  398.         sivc_dnr := nil;
  399.         state := ST_None;
  400.         tref := nil;
  401.         idle_til := TickCount;
  402.         GetVersion(app_resfile, vers);
  403.         app_creator := '????';
  404.         bndl := Get1Resource('BNDL', 128);
  405.         if (bndl <> nil) & (bndl^ <> nil) & (GetHandleSize(bndl) >= 4) then begin
  406.             BlockMoveData(bndl^, @app_creator[1], 4);
  407.         end;
  408.         query_result:= NewHandle(0);
  409.         GetDateTime(date);
  410.         SetDefaultLong(PC_FirstCheckSIVC,date);
  411.         SetDefaultLong(PC_LastCheckSIVCQuantum,-1234);
  412.         SetDefaultLong(PC_CheckSIVCPeriod,10080); { 1 week }
  413.         SetDefaultLong(PC_LastSIVC,bad_date);
  414.         SetDefaultLong(PC_SIVCUsers,-1);
  415.         first_ever_sivc := not prefs.ExistsTag(PC_UseSIVC);
  416.         junk := WritePrefsData;
  417.         InitSIVC := noErr;
  418.     end;
  419.     
  420.     procedure FinishSIVC;
  421.     begin
  422.         ReleaseConnection;
  423.         state := ST_Finished;
  424.         DisposeHandle(query_result);
  425.     end;
  426.         
  427.     procedure ConfigureSIVC(newversion : SIVCNewVersionCallBack; getsocks:SIVCGetSOCKSServerCallBack);
  428.     begin
  429.         StartupSIVC;
  430.         newversion_callback := newversion;
  431.         getsocks_callback := getsocks;
  432.     end;
  433.     
  434.     procedure StartupSIVC;
  435.     begin
  436.         StartupTransport;
  437.         StartupTranslateISO;
  438.         SetStartup(InitSIVC, IdleSIVC, 10, FinishSIVC);
  439.     end;
  440.     
  441. end.
  442.